#include "unitconverter.h"
#include <QSettings>
#include <iostream>

struct Unit
{
	QString name;
	double k;
};

const Unit weights[] = {
	{"milligram (mg)", 1E-3}, 
	{"grain (gr)", 64.79891E-3},
	{"gram (g)", 1},
	{"dram (dr)", 1.7718451953125},
	{"ounce (oz)", 28.349523125},
	{"pound (lb)", 453.59237},
	{"killogram (kg)", 1000},
	{"hundredweight (cwt)", 45.359237E+3},
	{"(short) ton", 907.18474E+3},
	{"tonn", 1000E+3}
}; 

const Unit volumes[] = {
	{"minim (min)", 0.06161152E-3 },// mL
	{"cubic centimeter (cc)", 1E-3},
	{"milliliter (mL)", 1E-3},
	{"fluid dram (fl dr)", 3.696691E-3 },// mL
	{"cubic inch (cu in)", 16.387064E-3 },// mL[6]
	{"fluid ounce (fl oz)", 29.57353E-3 },// mL
	{"gill (gi)", 118.2941E-3 },// mL
	{"cup (cp) or (c)", 236.5882E-3 },// mL
	{"(liquid) pint (pt)", 473.1765E-3 },// mL
	{"(liquid) quart (qt)", 946.3529E-3 },// mL
	{"liter (L)", 1},
	{"gallon (gal)", 3.785412 },// L
	{"cubic foot (cu ft)", 28.316846592 },// L
	{"beer barrel (bbl)", 117.3478 },// L
	{"oil barrel (bbl)", 158.9873 },// L
	{"hogshead", 238.4810 },// L
	{"cubic yard (cu yd)", 764.554857984 },// L
};

const Unit lengths[] = {
	{"millimetre (mm)", 1E-3},
	{"inch (in)", 25.4E-3 },// mm
	{"centimetre (cm)", 0.01},
	{"link (li)", 0.201168 },//  m
	{"foot (ft)", 0.3048 },//  m
	{"foot (survey)", 0.3048006 },//  m
	{"yard (yd)", 0.9144 },//  m
	{"metre (m)", 1},
	{"rod (rd)", 5.029210 },//  m
	{"chain (ch)", 20.1168 },//  m
	{"kilometre (km)", 1E+3},
	{"mile (mi)", 1.609344E+3 },//  km
	{"mile (survey)", 1.609347E+3 }//  km
};

UnitConverter::UnitConverter(QWidget *parent)
    : QWidget(parent)
{
	ui.setupUi(this);
    connect(ui.temperature, SIGNAL(toggled(bool)), this, SLOT(temperatureUnitSelected(bool)));
    connect(ui.weight, SIGNAL(toggled(bool)), this, SLOT(weightUnitSelected(bool)));
    connect(ui.length, SIGNAL(toggled(bool)), this, SLOT(lengthUnitSelected(bool)));
    connect(ui.volume, SIGNAL(toggled(bool)), this, SLOT(volumeUnitSelected(bool)));
    connect(ui.to, SIGNAL(currentRowChanged(int)), this, SLOT(calc()));
    connect(ui.from, SIGNAL(currentRowChanged(int)), this, SLOT(calc()));
    connect(ui.fromValue, SIGNAL(editingFinished()), this, SLOT(calc()));
    QSettings s("TeAnton", "USUnitConverter");
    setUnit(s.value("unit", 0).toInt());
}

enum {TEMPERATURE, WEIGHT, LENGTH, VOLUME};

int UnitConverter::unit()
{
	if (ui.temperature->isChecked())
		return TEMPERATURE;
	if (ui.weight->isChecked())
		return WEIGHT;
	if (ui.length->isChecked())
		return LENGTH;
//	if (ui.volume->checked())
		return VOLUME;
}

void UnitConverter::setUnit(int v)
{
	switch (v)
	{
		case TEMPERATURE: ui.temperature->setChecked(true);
			break;
		case WEIGHT: ui.weight->setChecked(true);
			break;
		case LENGTH: ui.length->setChecked(true);
			break;
		default /*case VOLUME*/: ui.volume->setChecked(true);
	}
}

void addWeights(QListWidget *v)
{/*
grain 	64,79891 mg 		
dram (dr) 	1,7718451953125 g
ounce (oz) 28,349523125 g 		
pound (lb) 	453,59237 g
hundredweight (cwt) 	45.359237 	
(short) ton 	907,18474 kg */
	v->clear();
	for (const Unit *i = weights; i != weights + sizeof(weights) / sizeof(Unit); ++i) 
		v->addItem(i -> name);
}

void UnitConverter::weightUnitSelected(bool checked)
{
	if (checked)
	{
		QSettings s("TeAnton", "USUnitConverter");
		int from = s.value("weightFrom", 0).toInt();
		int to = s.value("weightTo", 0).toInt();
		QString v = s.value("weightValue").toString();
		addWeights(ui.from);
		addWeights(ui.to);
		ui.fromValue -> setText(v);
		ui.from->setCurrentRow(from);
		ui.to->setCurrentRow(to);
	}
}

void addLengths(QListWidget *v)
{ /*
1 inch (in) 		25.4 mm
1 foot (ft) 	12 in 	0.3048 m
1 yard (yd) 	3 ft 	0.9144 m
1 mile (mi) 	5,280 ft 	1.609344 km
Survey
1 link (li) 	33⁄50 ft 	0.201168 m
1 foot (survey) 	1200⁄3937 m 	0.3048006 m
1 rod (rd) 	25 li 	5.029210 m
1 chain (ch) 	4 rd 	20.1168 m
1 mile (survey) 	80 ch 	1.609347 km */
	v->clear();
	for (const Unit *i = lengths; i != lengths + sizeof(lengths) / sizeof(Unit); ++i)
		v->addItem(i->name);
}

void UnitConverter::lengthUnitSelected(bool checked)
{
	if (checked)
	{
		QSettings s("TeAnton", "USUnitConverter");
		int from = s.value("lengthFrom", 0).toInt();
		int to = s.value("lengthTo", 0).toInt();
		QString v = s.value("lengthValue").toString();
		addLengths(ui.from);
		addLengths(ui.to);
		ui.to->addItem("foot inch");
		ui.from->addItem("foot inch");
		ui.fromValue->setText(v);
		ui.from->setCurrentRow(from);
		ui.to->setCurrentRow(to);
	}
}

void addVolumes(QListWidget *v)
{/*
Volume in general
Unit 	Divisions 	SI Equivalent
1 cubic inch (cu in) 		16.387 064 mL[6]
1 cubic foot (cu ft) 	1 728 cu in 	28.316 846 592 L
1 cubic yard (cu yd) 	27 cu ft 	764.554 857 984 L
or
0.764 554 857 984 m³

[edit] Liquid volume

Most important measures shown in bold font
Unit 	Divisions 	SI Equivalent
1 minim (min) 		0.061 611 52 mL
1 fluid dram (fl dr) 	60 min 	3.696 691 mL
1 fluid ounce (fl oz) 	8 fl dr 	29.573 53 mL
1 gill (gi) 	4 fl oz 	118.294 1 mL
1 cup (cp) or (c) 	2 gi or 8 fl oz 	236.588 2 mL
1 (liquid) pint (pt) 	2 cups or 4 gi or 16 fl oz 	473.176 5 mL
1 (liquid) quart (qt) 	2 pt or 32 fl oz 	946.352 9 mL
1 gallon (gal) 	4 qt or 128 fl oz or 231 cu in 	3.785 412 L
1 beer barrel (bbl) 	31 gal 	117.347 8 L
1 oil barrel (bbl) 	42 gal 	158.987 3 L
1 hogshead 	63 gal 	238.481 0 L */
	v->clear();
	for (const Unit *i = volumes; i != volumes + sizeof(volumes) / sizeof(Unit); ++i) 
		v->addItem(i -> name);
}


void UnitConverter::volumeUnitSelected(bool checked)
{
	if (checked)
	{
		QSettings s("TeAnton", "USUnitConverter");
		int from = s.value("volumeFrom", 0).toInt();
		int to = s.value("volumeTo", 0).toInt();
		QString v = s.value("volumeValue", "").toString();
		addVolumes(ui.from);
		addVolumes(ui.to);
		ui.fromValue->setText(v);
		ui.from->setCurrentRow(from);
		ui.to->setCurrentRow(to);
	}
}

void addTemperatures(QListWidget *v)
{
	v->clear();
	v->addItem("kelvin (K)");
	v->addItem("Celsius (C)");
	v->addItem("Fahrenheit (F)");
}

void UnitConverter::temperatureUnitSelected(bool checked)
{
	if (checked)
	{
		QSettings s("TeAnton", "USUnitConverter");
		int from = s.value("temperatureFrom", 0).toInt();
		int to = s.value("temperatureTo", 0).toInt();
		QString v = s.value("temperatureValue").toString();
		addTemperatures(ui.from);
		addTemperatures(ui.to);
		ui.fromValue->setText(v);
		ui.from->setCurrentRow(from);
		ui.to->setCurrentRow(to);
	}
}

UnitConverter::~UnitConverter()
{
	QSettings s("TeAnton", "USUnitConverter");
    s.setValue("unit", unit());
}

void UnitConverter::calc()
{
	QSettings s("TeAnton", "USUnitConverter");
	bool ok;
	double v = ui.fromValue->text().toDouble(&ok);
	
	if (!ok)
		v = 0;
	double c;
	switch (unit())
	{
		case TEMPERATURE:
			switch (ui.from->currentRow())
			{
				case 0: c = v - 273.15;
					break;
				case 1: c = v;
					break;
				default /*case 2*/: c = 5 * (v - 32) / 9;
					break; 
			}
			switch (ui.to->currentRow())
			{
				case 0: c = c + 273.15;
					break;
				case 1: c = c;
					break;
				default /*case 2*/: c = 9 * c / 5 + 32;
					break; 
			}
			s.setValue("temperatureValue", ui.fromValue->text());
			s.setValue("temperatureFrom", ui.from->currentRow());
			s.setValue("temperatureTo", ui.to->currentRow());
			ui.toValue->setText(QString::number(c));
			break;
		case WEIGHT:
			c = v * weights[ui.from->currentRow()].k / weights[ui.to->currentRow()].k;
			s.setValue("weightValue", ui.fromValue->text());
			s.setValue("weightFrom", ui.from->currentRow());
			s.setValue("weightTo", ui.to->currentRow());
			ui.toValue->setText(QString::number(c));
			break;
		case LENGTH:
			if (ui.from->currentRow() >= static_cast<int>(sizeof(lengths) / sizeof(Unit)))
			{
				QStringList l = ui.fromValue->text().split(" ");
				if (l.size() >= 1)  
				{
					c = l[0].toDouble() * 0.3048;
					if (l.size() >= 2)
						c += l[1].toDouble() *25.4E-3; 
				}
				else
					c = 0;
			}
			else
				c = v * lengths[ui.from->currentRow()].k;
				
			if (ui.to->currentRow() >= static_cast<int>(sizeof(lengths) / sizeof(Unit)))
				ui.toValue->setText(
					QString::number(static_cast<int>(c / 0.3048)) + " " + 
					QString::number((c / 0.3048 - static_cast<int>(c / 0.3048)) * 12, 'g', 2)
				);
			else
			{
				c = c / lengths[ui.to->currentRow()].k;
				ui.toValue->setText(QString::number(c));
			}
			s.setValue("lengthValue", ui.fromValue->text());
			s.setValue("lengthFrom", ui.from->currentRow());
			s.setValue("lengthTo", ui.to->currentRow());
			break;
		default: /*case VOLUME*/
			c = v * volumes[ui.from->currentRow()].k / volumes[ui.to->currentRow()].k;
			s.setValue("volumeValue", ui.fromValue->text());
			s.setValue("volumeFrom", ui.from->currentRow());
			s.setValue("volumeTo", ui.to->currentRow());
			ui.toValue->setText(QString::number(c));
	}
}
